package com.sl.utils.str;

import java.util.*;

/**
 * @author ：zhangC
 * @date ：Created in 2021/1/25 11:16
 * @description：\
 * @version: $2.0
 */
public class HFTEST {
    public static List<hardwareInfo.utils.HuffmanCodeNode> getNodes(String str) {
        // 存放所有的节点
        ArrayList<hardwareInfo.utils.HuffmanCodeNode> nodes = new ArrayList<>();
        // 临时存放节点的符号与权值
        HashMap<Byte, Integer> nodeMap = new HashMap<>();
        byte[] strBytes = str.getBytes();
        // 计算字符串中每个字符的权值
        for (byte strByte : strBytes) {
            if (nodeMap.get(strByte) == null) {
                nodeMap.put(strByte, 1);
            }
            else {
                nodeMap.put(strByte, nodeMap.get(strByte) + 1);
            }
        }
        Set<Map.Entry<Byte, Integer>> entrySet = nodeMap.entrySet();
        // 将所有节点加入到列表中
        for (Map.Entry<Byte, Integer> byteIntegerEntry : entrySet) {
            nodes.add(new hardwareInfo.utils.HuffmanCodeNode(byteIntegerEntry.getKey(), byteIntegerEntry.getValue()));
        }
        // 返回所有节点的符号与权值
        return nodes;
    }
    // 构造哈夫曼树
    public static hardwareInfo.utils.HuffmanCodeNode createHuffmanCodeTree(List<hardwareInfo.utils.HuffmanCodeNode> huffmanCodeNodes) {
        while (huffmanCodeNodes.size() > 1) {
            // 根据权值对节点进行升序排序
            Collections.sort(huffmanCodeNodes);
            // 获取最小权值的节点
            hardwareInfo.utils.HuffmanCodeNode leftNode = huffmanCodeNodes.remove(0);
            // 获取第二小权值的节点
            hardwareInfo.utils.HuffmanCodeNode rightNode = huffmanCodeNodes.remove(0);
            // 构造父节点
            hardwareInfo.utils.HuffmanCodeNode parent = new hardwareInfo.utils.HuffmanCodeNode(null, leftNode.getValue() + rightNode.getValue());
            parent.setLeftNode(leftNode);
            parent.setRightNode(rightNode);
            // 将父节点添加进列表中，继续参与运算
            huffmanCodeNodes.add(parent);
        }
        // 返回树的根节点
        return huffmanCodeNodes.get(0);
    }
    static StringBuilder stringBuilder = new StringBuilder();
    // 保存符号与该符号对应的哈夫曼编码
    static HashMap<Byte, String> hashMap = new HashMap<>();

    // 重载 getHuffmanCodes
    public static Map<Byte, String> getHuffmanCodes(hardwareInfo.utils.HuffmanCodeNode root) {
        if (root == null) {
            return null;
        }
        // 向左递归
        getHuffmanCodes(root.getLeftNode(), "0", stringBuilder);
        // 向右递归
        getHuffmanCodes(root.getRightNode(), "1", stringBuilder);
        return hashMap;
    }

    // 得到哈夫曼编码
    private static void getHuffmanCodes(hardwareInfo.utils.HuffmanCodeNode node, String code, StringBuilder sb) {
        StringBuilder stringBuilder = new StringBuilder(sb);
        // 追加当前节点的编码
        stringBuilder.append(code);
        if (node != null) {
            if (node.getCharacter() == null) {  // 如果是非叶子节点
                // 向左递归
                getHuffmanCodes(node.getLeftNode(), "0", stringBuilder);
                // 向右递归
                getHuffmanCodes(node.getRightNode(), "1", stringBuilder);
            } else {  // 如果是叶子节点
                hashMap.put(node.getCharacter(), stringBuilder.toString());
            }
        }
    }
    /**
     * 使用哈夫曼编码压缩字符串
     * @param strBytes  要压缩的字符串的字节数组
     * @param huffmanCodes  节点的哈夫曼编码
     * @return  压缩后的字节数组
     */
    public static byte[] zip(byte[] strBytes, Map<Byte, String> huffmanCodes) {
        StringBuilder sb = new StringBuilder();
        byte[] huffmanCodesBytes = null;
        for (byte charByte : strBytes) {
            sb.append(huffmanCodes.get(charByte));
        }
        if (sb.length() % 8 == 0) {
            huffmanCodesBytes = new byte[sb.length() / 8];
        } else {
            huffmanCodesBytes = new byte[sb.length() / 8 + 1];
        }
        int index = 0;
        for (int i = 0; i < sb.length(); i += 8) {
            if (i + 8 > sb.length()) {
                huffmanCodesBytes[index] = (byte) Integer.parseInt(sb.substring(i), 2);
            } else {
                huffmanCodesBytes[index] = (byte) Integer.parseInt(sb.substring(i, i + 8), 2);
            }
            index++;
        }
        return huffmanCodesBytes;
    }
    // 重载 zip() 方法
    public static byte[] zip(String str) {
        byte[] strBytes = str.getBytes();
        List<hardwareInfo.utils.HuffmanCodeNode> nodes = getNodes(str);
        hardwareInfo.utils.HuffmanCodeNode root = createHuffmanCodeTree(nodes);
        Map<Byte, String> huffmanCodes = getHuffmanCodes(root);
        byte[] huffmanCodesBytes = zip(str.getBytes(), huffmanCodes);
        return huffmanCodesBytes;
    }

    public static void main(String[] args) {
        String str = "eyJjcHVTZXJpYWwiOiJCRkVCRkJGRjAwMDkwNkU5IiwibWFjQWRkcmVzcyI6WyIxOC02MC0yNC05OC1DRC1GNiJdLCJtYWluQm9hcmRTZXJpYWwiOiJQR1dWQzBBQ1lBSjFRQyJ9";
        String str1 = "{\"cpuSerial\":\"BFEBFBFF000906E9\",\"macAddress\":[\"18-60-24-98-CD-F6\"],\"mainBoardSerial\":\"PGWVC0ACYAJ1QC\"}";
        byte[] zip = zip(str1);
        System.out.println(Arrays.toString(zip));
    }

}
